fix(mcp): suppress AuthlibDeprecationWarning from authlib.jose imports#40977
Conversation
authlib.jose is deprecated in favor of joserfc, but fastmcp (a hard dependency of the MCP service) still imports authlib.jose internally. We cannot migrate the caught error classes to joserfc.errors because the exceptions raised by fastmcp's jwt.decode() are authlib.jose.errors.*, not joserfc.errors.* — swapping the catch clauses would silently stop catching real JWT errors. Wraps each `from authlib.jose.errors import ...` in `warnings.catch_warnings()` so the AuthlibDeprecationWarning that fires on first import (authlib 1.3+) is suppressed at the callsite where we trigger it. Once fastmcp migrates to joserfc the workaround can be removed and the imports replaced with joserfc equivalents. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Code Review Agent Run #40526eActionable Suggestions - 0Review Details
Bito Usage GuideCommands Type the following command in the pull request comment and save the comment.
Refer to the documentation for additional commands. Configuration This repository uses Documentation & Help |
✅ Deploy Preview for superset-docs-preview ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Codecov Report❌ Patch coverage is
❌ Your project check has failed because the head coverage (99.95%) is below the target coverage (100.00%). You can increase the head coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## master #40977 +/- ##
==========================================
- Coverage 64.29% 64.29% -0.01%
==========================================
Files 2657 2657
Lines 144027 144061 +34
Branches 33207 33215 +8
==========================================
+ Hits 92604 92622 +18
- Misses 49803 49815 +12
- Partials 1620 1624 +4
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
authlib 1.3+ emits AuthlibDeprecationWarning (configured as "always") when authlib.jose is first imported. The warning fires from fastmcp's own authlib.jose import — not from the superset.mcp_service files — so wrapping our error-class imports in catch_warnings() was a no-op. The correct fix is a module-level warnings.filterwarnings() call in superset/mcp_service/__init__.py, which Python always runs before any submodule import. This ensures the filter is active before fastmcp triggers the authlib.jose import in both the production server path and test imports. Also adds authlib to _suppress_third_party_warnings() in server.py for defense in depth (covers any late authlib.jose imports during tool execution). The error classes remain from authlib.jose.errors — not joserfc.errors — because fastmcp's jwt.decode() raises authlib.jose.errors.* subclasses. Migrating the exception catch clauses to joserfc would silently stop catching real JWT errors until fastmcp itself migrates. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Code Review Agent Run #d373e7Actionable Suggestions - 0Additional Suggestions - 2
Review Details
Bito Usage GuideCommands Type the following command in the pull request comment and save the comment.
Refer to the documentation for additional commands. Configuration This repository uses Documentation & Help |
aminghadersohi
left a comment
There was a problem hiding this comment.
Review of 871c6db
Small, targeted fix — the approach is sound and consistent with the existing marshmallow/google suppression patterns in _suppress_third_party_warnings(). Two suggestions below.
MEDIUM — Missing category makes filter broader than necessary
superset/mcp_service/__init__.py:45-48 and superset/mcp_service/server.py:81-84
Both filterwarnings calls omit the category parameter, which defaults to Warning (the root class), meaning the filter matches any warning category whose message matches the regex. The authlib deprecation uses AuthlibDeprecationWarning(DeprecationWarning) (defined in authlib/deprecate.py). Adding category=DeprecationWarning constrains the match to deprecation warnings only, consistent with how the marshmallow filter specifies category=DeprecationWarning and the google filter specifies category=FutureWarning in the same function.
Unlikely to cause harm in practice (the message regex is very specific), but easy to tighten:
warnings.filterwarnings(
"ignore",
message=r"authlib\.jose module is deprecated",
category=DeprecationWarning,
)LOW — Test not updated for the new filter
test_suppress_third_party_warnings (tests/unit_tests/mcp_service/test_mcp_server.py:112) asserts the marshmallow and google filters are installed but doesn't check the new authlib filter. Adding a matching assertion would catch accidental removal:
authlib_filters = [
f
for f in warnings.filters
if f[0] == "ignore"
and isinstance(f[1], re.Pattern)
and f[1].pattern == r"authlib\.jose module is deprecated"
]
assert len(authlib_filters) >= 1, "Expected authlib deprecation filter"LOW — Superset's own authlib.jose imports
The PR comment attributes the warning to fastmcp, but Superset itself also imports from the deprecated module (jwt_verifier.py:38, mcp_config.py:23). These will also trigger the warning once authlib is upgraded past 1.6.x (currently pinned at 1.6.12). The suppression is a fine stopgap, but worth tracking a follow-up to migrate those imports to joserfc.
Overall this is clean and well-commented. The two actionable items (add category=DeprecationWarning, extend the test) are small.
aminghadersohi
left a comment
There was a problem hiding this comment.
Two small consistency/coverage notes on the warning suppression — neither blocking.
MEDIUM — specify category=DeprecationWarning for consistency and narrowness. Both new warnings.filterwarnings(...) calls (superset/mcp_service/__init__.py:45 and superset/mcp_service/server.py:81) omit the category argument, so they default to the root Warning class and match any category whose message matches the regex. The adjacent filters in _suppress_third_party_warnings() are explicit — marshmallow uses category=DeprecationWarning (server.py:70) and google uses category=FutureWarning (server.py:75). AuthlibDeprecationWarning subclasses DeprecationWarning, so adding category=DeprecationWarning keeps the new filters consistent with the surrounding code and slightly narrows the match. The message regex is specific enough that this is unlikely to cause harm in practice.
LOW — test_suppress_third_party_warnings doesn't assert the new authlib filter. tests/unit_tests/mcp_service/test_mcp_server.py checks the marshmallow and google filters but not the authlib one, so it won't catch an accidental removal. An authlib_filters assertion mirroring the existing two would close the gap.
For a follow-up (not this PR): Superset's own code imports from the deprecated module (superset/mcp_service/jwt_verifier.py:38, superset/mcp_service/mcp_config.py:23), so the eventual migration off authlib.jose should cover those first-party imports too, not just the fastmcp-triggered one.
What's the problem?
authlib1.3+ marksauthlib.joseas deprecated and emitsAuthlibDeprecationWarning(configured as"always") every timeauthlib.joseis first imported per process.fastmcp(the MCP transport) importsauthlib.joseduring its own startup, so every Superset MCP worker logs this on boot, polluting Datadog.Root cause
The warning fires when
fastmcp/server/auth/providers/jwt.pyrunsfrom authlib.jose import JsonWebKey, JsonWebToken. This happens during the import ofsuperset.mcp_service.jwt_verifier(which importsfastmcp). Anywarnings.catch_warnings()block placed injwt_verifier.pyormcp_config.pyafter their fastmcp imports is a no-op —authlib.joseis already insys.modules.Fix
A single
warnings.filterwarnings()call insuperset/mcp_service/__init__.py. Python always runs package__init__.pybefore any submodule import, so the filter is active before fastmcp triggersauthlib.jose. This covers both the production server path (server.py → jwt_verifier.py → fastmcp) and direct test imports.Also adds authlib to
_suppress_third_party_warnings()inserver.pyfor defense in depth.Why not migrate to
joserfc.errors?fastmcp'sjwt.decode()raisesauthlib.jose.errors.*. Changing our catch clauses tojoserfc.errors.*would silently stop catching real JWT signature/expiry errors until fastmcp migrates. The current error classes are correct.Files changed
superset/mcp_service/__init__.py— module-levelfilterwarningsbefore any submodule import firessuperset/mcp_service/server.py— adds authlib to_suppress_third_party_warnings()for defense in depthsuperset/mcp_service/jwt_verifier.py— restores normal import position (filter now handled by__init__.py)superset/mcp_service/mcp_config.py— sametests/unit_tests/mcp_service/test_jwt_verifier.py— sameNo behavior change
Warning suppression only. Exception handling is identical to before.
Test plan
pytest tests/unit_tests/mcp_service/test_jwt_verifier.py— all existing tests passAuthlibDeprecationWarningis not emitted on MCP service startup